from . import passport_api
# 导入请求上下文，转换json格式函数,返回参数的函数make_response,状态保持session
from flask import request, jsonify, make_response, current_app,session
# 导入constants常用参数
from info import constants
# 导入返回常用参数
from info.utils.response_code import RET
# 导入校验图片验证码的函数
from info.utils.captcha.captcha import captcha
# 导入redis_store数据库
from info import redis_store, db
# 导入re模块,随机数模块
import re, random
# 导入云通讯模板
from info.libs.yuntongxun.sms import CCP
#  导入mysql数据库对象
from info.models import User
# 导入日期生成函数
from datetime import datetime


# 创建视图函数，实现验证码功能
@passport_api.route('/image_code')
def passport():
    # 接口流程： 接收数据，校验数据，业务处理，返回结果
    """
    1 接收前端生成UUID，查询字符串形式，args
    2 校验UUID是否存在，如果不存在，return
    3 调取图片生成器生成图片验证码和图片
    4 拼接字符串,讲验证码保存在redis中
    5 返回图片本身，使用相应对象
    6 修改响应数据类型

    :return:
    """
    image_code_id = request.args.get('image_code_id')
    # 判断是否存在
    if not image_code_id:
        return jsonify(errno=RET.PARAMERR, errmsg='参数缺失')
    # 调用生成图片验证码的函数
    name, text, image = captcha.generate_captcha()
    print(text)
    # 在数据库中存储图片验证码信息
    try:
        redis_store.setex('ImageCode_' + image_code_id, constants.IMAGE_CODE_REDIS_EXPIRES, text)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='图片验证码存储失败')
    else:
        # 返回图片给前端
        response = make_response(image)
        # 响应格式改变
        response.headers['Content-Type'] = 'application/json'
        return response


# 创建视图函数,发送短信验证码
@passport_api.route('/sms_code', methods=['GET', 'POST'])
def send_sms_code():
    """
    1 获取前端传回来的信息,post请求的json数据 电话号码,图片验证码,UUID等
    2 判断是否存在 all
    3 校验电话号码是否正确 正则
    5 获取数据库验证码
    6 如果不存在,直接终止程序执行
    7 如果存在,删除图片验证码
    8 进行验证码比对
    9 判断手机号是否已经注册
    10 生成6位随机数
    11 在redis中存储随机数
    12 调用云通讯发送手机验证码,
    13 检查短信是否发送成功

    遇到的错误:
        1 实例化ccp对象的时候,实例化,传参
        2 校验图片验证码,取出来,判断是否存在,不存在返回验证码失效,存在先删除验证码
        3 加csrf的时候不小心把注释给解放了,导致无法执行js代码
        4 ajax的方法,contentType:  headers:{}
        5 ajax发送不成功可能是没有注册

    :return:
    """
    mobile = request.json.get('mobile')
    image_code = request.json.get('image_code')
    image_code_id = request.json.get('image_code_id')
    # 1 校验是否存在
    if not all([mobile, image_code, image_code_id]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数不完整')
    # 2 校验手机号是否正确,导入re模块
    if not re.match(r'^1[3456789]\d{9}$', mobile):
        return jsonify(errno=RET.PARAMERR, errmsg='手机号输入错误')

    # 3 获取redis中的验证码
    try:
        real_image_code = redis_store.get('ImageCode_' + image_code_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='验证码查询失败')
    # 4 判断验证码是否存在,不存在返回不存在
    if not real_image_code:
        return jsonify(errno=RET.DATAEXIST, errmsg='数据不存在')
    # 5 如果存在删除图片验证码
    else:
        redis_store.delete('Image_code_' + image_code_id)
    # 6 真实验证码与前端发过来的验证码进行比对
    if image_code != real_image_code:
        return jsonify(errno=RET.PARAMERR, errmsg='验证码错误')
    # 7 查询数据库判断用户是否存在
    try:
        user = User.query.get(mobile=mobile)
    except Exception as e:
        current_app.logger.error(e)
    else:
        if user is not None:
            return jsonify(errno=RET.DATAEXIST, errmsg='该用户已存在')
    # 7 生成6位数动态短信验证码
    sms_code = '%06d' % random.randint(1, 999999)
    print(sms_code)
    # 8 redis存储短信验证码
    try:
        redis_store.setex('SmsCode_' + mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='验证码存储失败')
    # 9 调用云通讯发送短信
    try:
        ccp = CCP()
        result = ccp.send_template_sms(mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES / 60], 1)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.THIRDERR, errmsg='第三方错误')
    else:
        # 判断短信是否发送成功
        if 0 == result:
            return jsonify(errno=RET.OK, errmsg='短信发送成功')
        else:
            return jsonify(errno=RET.PARAMERR, errmsg='短信发送失败')


@passport_api.route('/register', methods=['GET', 'POST'])
def register():
    '''
    注册: 接收数据,校验数据,处理业务,返回结果
    1 接收前端发送的三个数据,电话,短信校验码,密码
    2 校验参数完整性
    3 校验手机号是否符合规格
    4 从redis数据库提取验证码
    5 验证码不存在返回验证码过期
    6 比较验证码和前端数据是否一直
    7 校验用户是否注册过
    8 校验密码是否符合规格
    9 构造模型类对象,保存用户到数据库
    10 调用redis存储nick_name为手机号,用户id,用户手机号
    :return:
    '''
    mobile = request.json.get('mobile')
    sms_code = request.json.get('sms_code')
    password = request.json.get('password')
    # 校验参数完整性
    if not all([mobile, sms_code, password]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数缺失')
    # 校验手机号格式
    if not re.match(r'^1[3456789]\d{9}$', mobile):
        return jsonify(errno=RET.PARAMERR, errmsg='手机号码错误')
    # 从redis数据库中获取短信验证码
    try:
        real_sms_code = redis_store.get('SmsCode_' + mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='验证码获取失败')
    else:
        if real_sms_code is None:
            return jsonify(errno=RET.DATAEXIST, errmsg='验证码已失效')
    # 判断验证码是否正确
    if real_sms_code != sms_code:
        return jsonify(errno=RET.PARAMERR, errmsg='验证码输入错误')
    # 判断用户是否注册
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='获取用户信息失败')
    if user is not None:
        return jsonify(errno=RET.DATAEXIST, errmsg='用户已注册')
    # 构造模型类对象
    user = User()
    user.mobile = mobile
    user.nick_name = mobile
    user.password = password
    # 存储数据,session
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg='提交信息错误')
    # 把用户信息缓存到数据库中,使用session的好处是,不用怕重复赋值
    session['id'] = user.id
    session['nick_name'] = user.nick_name
    session['mobile'] = user.mobile
    # 返回信息
    return jsonify(errno=RET.OK, errmsg='注册成功')


@passport_api.route('/login', methods=['POST'])
def login():
    '''
    1 检验用户是否登陆
    2 获取前端传送的数据,
    3 校验账户是否存在
    4 校验密码是否匹配
    5 读取redis中存储的用户信息,展示到前端 页面
    :return:
    '''
    mobile = request.json.get('mobile')
    password = request.json.get('password')
    # 检验用户是否登陆
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='用户查询失败')
    # 如果存在用户
    # 校验密码,check_password是验证两个相等返回True
    if user is None or not user.check_password(password):
        return jsonify(errno=RET.DATAEXIST, errmsg='用户名或密码不正确')
    # 存储登陆时间
    user.last_login = datetime.now()
    # 存储用户时间信息
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg='数据存储失败')
    # 讲信息返回给前端
    session['user_id'] = user.id
    session['mobile'] = user.mobile
    session['nick_name'] = user.nick_name
    return jsonify(errno=RET.OK, errmsg='用户登陆成功')

# 用户登出
@passport_api.route('/logout', methods=['GET','POST'])
def logout():
    session.pop('user_id', None)
    session.pop('mobile', None)
    session.pop('nick_name', None)
    return jsonify(errno=RET.OK, errmsg='用户登出成功')
